package mammuthus.web.action;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.webdm.common.tools.NumberUtil;
import com.webdm.common.tools.StringUtil;
import mammuthus.client.ConfClient;
import mammuthus.client.ConfUtils;
import mammuthus.client.ZKClientWrapper;
import mammuthus.web.bean.ProjectConfBean;
import mammuthus.web.service.ProjectConfService;
import mammuthus.web.service.SlaveService;
import net.csdn.common.collections.WowCollections;
import net.csdn.common.settings.ImmutableSettings;
import net.csdn.common.settings.Settings;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import scala.Tuple4;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Created by fbj on 15-2-4 下午4:39.
 */
@Controller
public class ProjectConfAction  {


    private Logger logger = Logger.getLogger(ProjectConfAction.class);

    private ConfClient confClient = null;

    private ProjectConfService projectConfService;


    private SlaveService slaveService;

    private Settings settings;

    @Autowired
    public void setProjectConfService(ProjectConfService projectConfService) {
        this.projectConfService = projectConfService;
    }

    @Autowired
    public ProjectConfAction(SlaveService slaveService) {
        this.slaveService = slaveService;
        //优先检测是否已经安装有zookeeper集群，否则尝试使用配置。如果都没有，则禁用配置管理
        this.settings = ImmutableSettings.settingsBuilder().loadFromClasspath("./application.yml").build();
        configConfClient();
    }

    public void configConfClient() {
        try {
            String zookeeperHosts = settings.get("conf.zk");
            if (WowCollections.isEmpty(zookeeperHosts)) zookeeperHosts = WowCollections.join(slaveService.appSlave("zookeeper",false), ",");
            logger.info("zookeeperHosts "+zookeeperHosts);
            if (WowCollections.isEmpty(zookeeperHosts)) return;
            ZKClientWrapper zkClientWrapper = new ZKClientWrapper(settings);
            zkClientWrapper.configZkClient(zookeeperHosts);
            confClient = new ConfClient(settings, zkClientWrapper);
        } catch (Exception e) {
            logger.info("",e);
        }

    }

    @RequestMapping(value = "/conf/enable" +
            ".html", method = RequestMethod.GET)
    public String enableConfList(HttpServletRequest request,
                                 @RequestParam(value = "slaves", defaultValue = "") String slaves) {
        configConfClient();
        slaveService.enableConf(slaves);
        return "redirect:/conf/list.html";
    }

    @RequestMapping(value = "/conf/list.html", method = RequestMethod.GET)
    public String showConfList(HttpServletRequest request,
                               @RequestParam(value = "path", defaultValue = "/") String path,
                               @RequestParam(value = "conf_host_list", defaultValue = "false") String conf_host_list
    ) {
        //无法获取配置管理的基本要求
        if (confClient == null) {

            request.setAttribute("path", path);
            request.setAttribute("list", new ArrayList<Object[]>());
            request.setAttribute("page", "confManager");
            request.setAttribute("zookeeper", "missing");

            return "conf_list";
        }

        path = path.replaceAll("/+", "/");
        if (!"/".equals(path) && path.endsWith("/")) {
            path = path.substring(0, path.length() - 1);
        }

        List<Object[]> list = new ArrayList<Object[]>();
        List<String> hosts = new ArrayList<String>();
        for (Tuple4<String, String, Object, Date> t : confClient.list(path)) {
            list.add(new Object[]{t._1(), t._2(), t._3(), t._4()});
            if(path.startsWith("/_status")) {
                hosts.add(t._1());
            }
        }
        request.setAttribute("path", path);
        request.setAttribute("list", list);
        request.setAttribute("page", "confManager");
        request.setAttribute("hosts",WowCollections.join(hosts,","));
        request.setAttribute("zookeeper", "satisfied");
        request.setAttribute("conf_host_list",conf_host_list);


        return "conf_list";

    }

    @RequestMapping(value = "/conf/addPath.html")
    public String addPath(HttpServletRequest request,
                          @RequestParam(value = "name", defaultValue = "") String name,
                          @RequestParam(value = "path", defaultValue = "/") String path
    ) {


        if (name != null && !name.isEmpty() && !name.contains("/"))
            confClient.addConf(path + "/" + name, null);

        return "redirect:/conf/list.html?path=" + path;

    }

    @RequestMapping(value = "/conf/addConf.html")
    public String addConf(HttpServletRequest request,
                          @RequestParam(value = "path", defaultValue = "") String path,
                          @RequestParam(value = "version", defaultValue = "") String version,
                          @RequestParam(value = "comment", defaultValue = "") String comment,
                          @RequestParam(value = "conf", defaultValue = "") String conf

    ) {


        String result = "success";
        if (path.isEmpty()) {
            result = "path不能为空!";

        } else if (conf.isEmpty()) {
            result = "配置不能为空!";
        } else if (version.isEmpty()) {
            result = "版本不能为空!";
        } else {

            String finalConf = confClient.processConfChange(conf, ConfUtils.analyze(conf));
            String r = checkConf(finalConf, path);
            if (!"success".equals(r)) {
                result = "格式存在错误: " + r;
            } else if (projectConfService.isExist(path, version)) {
                result = "该版本已经存在!";
            } else {

                logger.info("添加配置, path [" + path + "], version [" + version + "], comment [" + comment + "], confLen " + (conf == null ? 0 : conf.length()));
                projectConfService.addVersion(path, version, comment, conf);
                confClient.updateConf(path, conf);
            }


        }


        logger.info("add conf, path " + path + ", result " + result);
        JSONObject obj = new JSONObject();
        obj.put("result", result);
        request.setAttribute("result", obj.toJSONString());
        //path = path.substring(0, path.lastIndexOf("/"));
        return "json";

    }

    @RequestMapping(value = "/conf/detail.html")
    public String detail(HttpServletRequest request,
                         @RequestParam(value = "path", defaultValue = "/") String path
    ) {


        if (path != null && !path.isEmpty()) {


            ProjectConfBean version = projectConfService.getLastedProjectConfByPath(path);

            String conf = confClient.getConf(path);
            processFileType(path, request);
            request.setAttribute("path", path);
            request.setAttribute("conf", conf);
            if (version != null) {
                logger.info("查看配置, path [" + path + "], version [" + version.getVersion() + "], comment [" + version.getComment() + "], confLen " + (conf == null ? 0 : conf.length()));

                request.setAttribute("version", version.getVersion());
                request.setAttribute("comment", version.getComment());
                request.setAttribute("versionFlag", true);
            } else {
                logger.info("path" + path + "不存在版本数据, confLen " + (conf == null ? 0 : conf.length()));
            }

        } else {
            logger.info("[detail] path为空");
        }

        request.setAttribute("page", "confManager");

        return "conf_detail";

    }

    @RequestMapping(value = "/conf/showFinal.html")
    public String showFinal(HttpServletRequest request,
                            @RequestParam(value = "path", defaultValue = "/") String path
    ) {


        if (!path.isEmpty()) {


            String conf = confClient.getFinalConf(path);
            processFileType(path, request);
            request.setAttribute("conf", conf);
            request.setAttribute("path", path);
            request.setAttribute("readonly", true);
        }

        request.setAttribute("page", "confManager");

        return "conf_detail";

    }

    @RequestMapping(value = "/conf/delete.html")
    public String delete(HttpServletRequest request,
                         @RequestParam(value = "path", defaultValue = "") String path,
                         @RequestParam(value = "parent", defaultValue = "/") String parent
    ) {


        if (!path.isEmpty()) {


            confClient.delete(path);
            request.setAttribute("path", path);
        }

        return "redirect:/conf/list.html?path=" + parent;

    }

    @RequestMapping(value = "/conf/versionList.html")
    public String versionList(HttpServletRequest request,
                              @RequestParam(value = "path", defaultValue = "") String path,
                              @RequestParam(value = "pageNum", defaultValue = "1") int pageNum,
                              @RequestParam(value = "pageSize", defaultValue = "100") int pageSize) {


        if (!path.isEmpty()) {

            List<ProjectConfBean> versions = projectConfService.getVersions(path, pageNum, pageSize);
            request.setAttribute("versions", versions);
        } else {
            logger.info("[versionList] path为空");
        }

        request.setAttribute("page", "confManager");

        return "conf_versionList";

    }

    @RequestMapping(value = "/conf/versionDetail.html")
    public String versionDetail(HttpServletRequest request,
                                @RequestParam(value = "id", defaultValue = "0") int id) {


        if (id > 0) {


            ProjectConfBean version = projectConfService.getProjectConfById(id);
            request.setAttribute("path", version.getPath());
            request.setAttribute("version", version.getVersion());
            request.setAttribute("comment", version.getComment());
            request.setAttribute("conf", version.getConf());
            request.setAttribute("versionFlag", true);
            processFileType(version.getPath(), request);
        }

        request.setAttribute("page", "confManager");

        return "conf_detail";

    }

    @RequestMapping(value = "/conf/versionRollback.html")
    public String versionRollback(HttpServletRequest request,
                                  @RequestParam(value = "id", defaultValue = "0") int id) {


        if (id > 0) {

            ProjectConfBean version = projectConfService.getProjectConfById(id);

            ProjectConfBean lastedVersion = projectConfService.getLastedProjectConfByPath(version.getPath());
            request.setAttribute("path", version.getPath());
            request.setAttribute("version", version.getVersion());
            request.setAttribute("comment", version.getComment());
            request.setAttribute("conf", version.getConf());
            request.setAttribute("versionFlag", true);


            String v = lastedVersion.getVersion();
            String newVersion = StringUtil.toString(System.currentTimeMillis());
            String arr[] = v.split("\\.");
            if (arr.length > 0) {
                arr[arr.length - 1] = StringUtil.toString(NumberUtil.getIntValue(arr[arr.length - 1]) + 1);
                newVersion = StringUtil.join(arr, ".");
            }
            projectConfService.addVersion(version.getPath(), newVersion, "回滚到版本" + version.getVersion(), version.getConf());
            confClient.updateConf(version.getPath(), version.getConf());
            return "redirect:/conf/versionList.html?path=" + version.getPath();
        } else {
            return "redirect:/list.html";
        }


    }

    public String checkConf(String conf, String path) {

        try {

            if (path.endsWith(".json")) {

                if (conf.startsWith("[")) {

                    JSON.parseArray(conf);
                } else {
                    JSON.parseObject(conf);
                }

            } else if (path.endsWith(".yml")) {

                ImmutableSettings.YamlSettingsLoader.load(conf);

            }

            return "success";
        } catch (Exception e) {

            return e.toString().replace("\"", "\\\"");
        }


    }


    private void processFileType(String path, HttpServletRequest request) {

        if (path.contains(".yml")) {
            request.setAttribute("js", "yaml/yaml.js");
            request.setAttribute("type", "text/x-yaml");
        } else if (path.contains(".properties") || path.contains(".ini")) {
            request.setAttribute("js", "properties/properties.js");
            request.setAttribute("type", "text/x-properties");
        } else if (path.contains(".json")) {
            request.setAttribute("js", "javascript/javascript.js");
            request.setAttribute("type", "application/json");
        } else {
            request.setAttribute("js", "javascript/javascript.js");
            request.setAttribute("type", "text/javascript");
        }

    }

}
